package com.github.hwangrq.myrpc.provider.myrpc.provider.handler;

import com.alibaba.fastjson.JSON;
import com.github.hwangrq.myrpc.api.common.RpcRequest;
import com.github.hwangrq.myrpc.api.common.RpcResponse;
import com.github.hwangrq.myrpc.provider.myrpc.provider.anno.RpcService;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.cglib.reflect.FastClass;
import org.springframework.cglib.reflect.FastMember;
import org.springframework.cglib.reflect.FastMethod;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


@Slf4j
@Component
@ChannelHandler.Sharable
public class RpcServerHandler extends SimpleChannelInboundHandler<String>
        implements ApplicationContextAware {

    private static final Map<Object, Object> SERVICE_INSTANCE_MAP = new ConcurrentHashMap<>();

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String, Object> servicesMap = applicationContext.getBeansWithAnnotation(RpcService.class);
        if (servicesMap.isEmpty()) { return; }
        servicesMap.forEach((beanName, serviceBean) -> {
            Class<?>[] interfaces = serviceBean.getClass().getInterfaces();
            if (interfaces.length > 0) {
                String interface1Name = serviceBean.getClass().getInterfaces()[0].getName();
                SERVICE_INSTANCE_MAP.put(interface1Name, serviceBean);
            } else {
                throw new RuntimeException("当前 service 服务 ["+ beanName +"] 没有实现接口");
            }
        });
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        RpcRequest rpcRequest = JSON.parseObject(msg, RpcRequest.class);
        RpcResponse rpcResponse = new RpcResponse();
        rpcResponse.setRequestId(rpcRequest.getRequestId());
        try {
            rpcResponse.setResult(handler(rpcRequest));

        } catch (Exception e) {
            System.out.println(e.getMessage());
            rpcResponse.setError(e.getMessage());
        }
        ctx.writeAndFlush(JSON.toJSONString(rpcResponse));
    }

    private Object handler(RpcRequest rpcRequest) throws InvocationTargetException {
        Object serviceBean = SERVICE_INSTANCE_MAP.get(rpcRequest.getClassName());
        if (serviceBean == null) {
            throw new RuntimeException("根据 beanName 找不到 service 服务：" + rpcRequest.getClassName());
        }
        Class<?> serviceBeanClass = serviceBean.getClass();
        String methodName = rpcRequest.getMethodName();
        Class<?>[] parameterTypes = rpcRequest.getParameterTypes();
        Object[] parameters = rpcRequest.getParameters();

        FastClass fastClass = FastClass.create(serviceBeanClass);
        FastMethod method = fastClass.getMethod(methodName, parameterTypes);
        return method.invoke(serviceBean, parameters);
    }

}
